2020-2021 Sunseeker Telemetry and Lighting System
saph_a_ex3_pulseGenerationDMA.c
Go to the documentation of this file.
1 /* --COPYRIGHT--,BSD
2  * Copyright (c) 2017, Texas Instruments Incorporated
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * * Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  *
12  * * Redistributions in binary form must reproduce the above copyright
13  * notice, this list of conditions and the following disclaimer in the
14  * documentation and/or other materials provided with the distribution.
15  *
16  * * Neither the name of Texas Instruments Incorporated nor the names of
17  * its contributors may be used to endorse or promote products derived
18  * from this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
22  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
27  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
28  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
29  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
30  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  * --/COPYRIGHT--*/
32 //******************************************************************************
33 // saph_a_ex3_pulseGenerationDMA.c - Pulse generation using the SAPH_A PPG/PHY and DMA.
34 //
35 // Description: Configure the PPG and PHY in the SAPH_A module manually (register
36 // mode instead of ASQ controlled) to generate 6(Can be more) sets of high frequency
37 // pulses on the dedicated CH0_OUT pin in Multi Tone mode, once per second.
38 // 6 sets of pulses(Can be defined by users):
39 // Pulses number: 2-4-3-3-4-4
40 // Pulses frequency(KHz): 625-1250-277-625-178-384
41 // ***NOTE: For the limitation of the DMA transmission speed, the minimum duration
42 // time of every set of pulses should be more than 4*(3+9) MCLK.***
43 //
44 // MSP430FR6043
45 // ---------------
46 // /|\| |
47 // | | |
48 // --|RST |
49 // | P1.0|---> LED
50 // | |-USSXTIN
51 // | |-USSXTOUT
52 // | CH0_OUT|---> 6 sets of pulses 1/sec
53 //
54 // Wallace Tran
55 // Texas Instruments Inc.
56 // January 2019
57 // Built with IAR Embedded Workbench V7.10 & Code Composer Studio V7.3
58 //******************************************************************************
59 #include "driverlib.h"
60 
61 uint16_t RAM_XE[20]; // => 3 E-puls phases x 3 Register + 2 X-puls phases x 3 register+3 STOP
62 uint16_t RAM_DMA_CONFIG[60]; // => (3 E-puls + 2 X-puls + 1 STOP)*9
63 //The address of RAM_DMA_CONFIG[] should be within 0xFFFF to make the minimum number of transmit data by DMA3 which is 9
64 uint16_t epulse[3] = {4,3,4}; // E-pulses number
65 uint16_t hper[3] = {8,16,26}; // High phase
66 uint16_t lper[4] = {8,16,26}; // Low phase
67 
68 uint16_t xpulse[2] = {3,4}; // X-pulses number
69 uint16_t xhper[2] = {36,56}; // High phase
70 uint16_t xlper[2] = {36,56}; // Low phase
71 
72 void HSPLL_routine(void);
73 void setup_DMA();
74 
75 int main(void)
76 {
77  // Stop WDT
78  WDT_A_hold(WDT_A_BASE);
79 
80  // Configure P1.0 as output for LED
81  GPIO_setAsPeripheralModuleFunctionOutputPin(
82  GPIO_PORT_P1,
83  GPIO_PIN0,
84  GPIO_PRIMARY_MODULE_FUNCTION
85  );
86 
87  // Disable the GPIO power-on default high-impedance mode to activate
88  // previously configured port settings
89  PMM_unlockLPM5();
90 
91  FRAMCtl_A_configureWaitStateControl(FRAMCTL_A_ACCESS_TIME_CYCLES_1);
92 
93  /* ---Begin Clock System Setup--- */
94  // Per Device Errata(CS12) set divider to 4 before changing frequency to
95  // prevent out of spec operation from overshoot transient
96  // Set all corresponding clk sources to divide by 4 for errata(CS12)
97  CS_initClockSignal(CS_SMCLK, CS_DCOCLK_SELECT, CS_CLOCK_DIVIDER_4);
98  CS_initClockSignal(CS_MCLK, CS_DCOCLK_SELECT, CS_CLOCK_DIVIDER_4);
99  CS_initClockSignal(CS_ACLK, CS_VLOCLK_SELECT, CS_CLOCK_DIVIDER_4);
100  // Set DCO to 8MHz
101  CS_setDCOFreq(CS_DCORSEL_1, CS_DCOFSEL_4);
102  // Delay by ~10us to let DCO settle. 60 cycles = 20 cycles buffer + (10us / (1/4MHz))
103  __delay_cycles(60);
104  // Set SMCLK = MCLK = DCO, ACLK = VLOCLK
105  // Set all dividers to 1 for MCLK = SMCLK = 16MHz operation
106  CS_initClockSignal(CS_SMCLK, CS_DCOCLK_SELECT, CS_CLOCK_DIVIDER_1);
107  CS_initClockSignal(CS_MCLK, CS_DCOCLK_SELECT, CS_CLOCK_DIVIDER_1);
108  CS_initClockSignal(CS_ACLK, CS_VLOCLK_SELECT, CS_CLOCK_DIVIDER_1);
109  /* ---End Clock System Setup--- */
110 
111  HSPLL_routine(); // Initialize the HSPLL and wait for it to lock
112 
113  setup_DMA(); // Initialize the DMA
114 
115  /* ---Begin setting up the PPG settings--- */
116  // Unlock the SAPH_A registers
117  SAPH_A_unlock(SAPH_A_BASE);
118 
119  // Set up the PHY to output PPG on dedicated CH0_OUT pin
120  SAPH_A_configPHYParam saphAPHYConfig = {0};
121  saphAPHYConfig.outputFunction = SAPH_A_PHY_OUTPUT_PULSEGENERATOR_SINGLE_DRIVE;
122  SAPH_A_configurePHY(SAPH_A_BASE, &saphAPHYConfig);
123 
124  // TA2.1 trigger, CH0 output, register mode
125  SAPH_A_configPPGParam saphAConfig = {0};
126  saphAConfig.enablePrescaler = SAPH_A_PPG_PRESCALER_ENABLE;
127  saphAConfig.triggerSource = SAPH_A_PPG_TRIGGER_SOURCE_TIMER;
128  saphAConfig.channelSelect = SAPH_A_PPG_CHANNEL_0;
129  saphAConfig.portSelect = SAPH_A_PPG_PORT_CHARGED_BY_PPG;
130  SAPH_A_configurePPG(SAPH_A_BASE, &saphAConfig);
131  /* ---End setting up the PPG settings--- */
132 
133  /* ---Begin configure TA2.1 for 1/sec to trigger the pulse generation and toggle LED--- */
134  Timer_A_initUpModeParam timerParam2 = {0};
135  timerParam2.timerPeriod = 9400;
136  TA2CCR1 = 4700;
137  TA2CCTL1 = OUTMOD_7 | CCIE; // Enable output signal to trigger PPG, enable interrupt
138  // Timer sourced from ACLK (VLO)
139  timerParam2.clockSource = TIMER_A_CLOCKSOURCE_ACLK;
140  // Clear timer
141  timerParam2.timerClear = TIMER_A_DO_CLEAR;
142  timerParam2.startTimer = true;
143  Timer_A_initUpMode(TA2_BASE, &timerParam2);
144  /* ---End configure TA2.1 for 1/sec to trigger the pulse generation and toggle LED--- */
145 
146  while(1)
147  {
148  __bis_SR_register(LPM0_bits | GIE); // Enter LPM0 enable interrupt
149  __no_operation();
150  }
151 }
152 
153 // Timer A2 interrupt service routine
154 #if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
155 #pragma vector = TIMER2_A1_VECTOR
156 __interrupt void Timer2_A1_ISR(void)
157 #elif defined(__GNUC__)
158 void __attribute__ ((interrupt(TIMER2_A1_VECTOR))) Timer2_A1_ISR (void)
159 #else
160 #error Compiler not supported!
161 #endif
162 {
163  SAPH_A_configXPGParam saphAXPGParam = {0};
164  DMA_initParam dmaParam = {0};
165  switch(__even_in_range(TA2IV, TAIV__TAIFG))
166  {
167  case TAIV__NONE: break; // No interrupt
168  case TAIV__TACCR1:
169  saphAXPGParam.eventType = SAPH_A_DMA_TRIGGER_EVENT;
170  saphAXPGParam.extendedMode = SAPH_A_DUAL_TONE_LOOP;
171  saphAXPGParam.extraPulses = 2;
172  SAPH_A_configureExtendedPPG(SAPH_A_BASE, &saphAXPGParam);
173 
174  SAPH_A_setXPGLowPeriod(SAPH_A_BASE, 16);
175  SAPH_A_setXPGHighPeriod(SAPH_A_BASE, 16);
176 
177  // Repeated block transfer, increase src address, increase dst address
178  dmaParam.channelSelect = DMA_CHANNEL_2;
179  dmaParam.transferModeSelect = DMA_TRANSFER_REPEATED_BLOCK;
180  DMA_init(&dmaParam);
181  DMA_setSrcAddress(DMA_CHANNEL_2, (uint32_t)(uintptr_t)&RAM_XE, DMA_DIRECTION_INCREMENT);
182  DMA_setDstAddress(DMA_CHANNEL_2, (uint32_t)(uintptr_t)&SAPHPGC, DMA_DIRECTION_INCREMENT);
183 
184  DMA_setTransferSize(DMA_CHANNEL_2, 3); // 3 registers per block
185  DMA_enableTransfers(DMA_CHANNEL_2);
186  // Write new SA and DA of DMA2
187  DMA_setSrcAddress(DMA_CHANNEL_2, (uint32_t)(uintptr_t)RAM_XE+3, DMA_DIRECTION_INCREMENT);
188  DMA_setDstAddress(DMA_CHANNEL_2, (uint32_t)(uintptr_t)&SAPHXPGCTL, DMA_DIRECTION_INCREMENT);
189 
190  // Repeated block transfer, increase src address, increase dst address
191  dmaParam.channelSelect = DMA_CHANNEL_3;
192  DMA_init(&dmaParam);
193  DMA_setSrcAddress(DMA_CHANNEL_3, (uint32_t)(uintptr_t)&RAM_DMA_CONFIG, DMA_DIRECTION_INCREMENT);
194  DMA_setDstAddress(DMA_CHANNEL_3, (uint32_t)(uintptr_t)&DMA2SA, DMA_DIRECTION_INCREMENT);
195 
196  DMA_setTransferSize(DMA_CHANNEL_3, 9); // 10 DMA registers
197  DMA_enableTransfers(DMA_CHANNEL_3);
198  // Write new SA of DMA3
199  DMA_setSrcAddress(DMA_CHANNEL_3, (uint32_t)(uintptr_t)RAM_DMA_CONFIG+9, DMA_DIRECTION_INCREMENT);
200 
201  GPIO_toggleOutputOnPin(GPIO_PORT_P1, GPIO_PIN0); // Toggle LED to show new cycle
202  break;
203  case TAIV__TAIFG: break; // overflow
204  default: break;
205  }
206 }
207 
208 void HSPLL_routine(void)
209 {
210  /* ---Begin initialize the HSPLL and wait for it to lock--- */
211  // Configure USSXT Oscillator
212  HSPLL_xtalInitParam param = {0};
213 // param.oscillatorType = HSPLL_XTAL_OSCTYPE_XTAL;
214  param.oscillatorType = 0x0000;
215  param.oscillatorEnable = HSPLL_XTAL_ENABLE;
216  param.xtlOutput = HSPLL_XTAL_OUTPUT_ENABLE;
217  HSPLL_xtalInit(HSPLL_BASE, &param);
218 
219  // Set up timer to wait in LPM for crystal stabilization time = 4096 clocks for crystal resonator.
220  // For 8MHz XTAL, 4096 clocks = 512us. Using VLO = 9.4kHz, wait 5 timer clock cycles = 532us.
221  Timer_A_initUpModeParam timerParam = {0};
222  timerParam.timerPeriod = 5;
223  timerParam.captureCompareInterruptEnable_CCR0_CCIE = TIMER_A_CCIE_CCR0_INTERRUPT_ENABLE;
224  // Timer sourced from ACLK (VLO)
225  timerParam.clockSource = TIMER_A_CLOCKSOURCE_ACLK;
226  // Clear timer
227  timerParam.timerClear = TIMER_A_DO_CLEAR;
228  timerParam.startTimer = true;
229  Timer_A_initUpMode(TA4_BASE, &timerParam);
230 
231  // Enter LPM3 w/interrupts enabled
232  __bis_SR_register(LPM3_bits | GIE);
233 
234  // For debugger
235  __no_operation();
236 
237  // Check if oscillator is stable
238  while(HSPLL_getOscillatorStatus(HSPLL_BASE) == HSPLL_OSCILLATOR_NOT_STARTED);
239 
240  // Output oscillator on pin
241  HSPLLUSSXTLCTL &= ~XTOUTOFF;
242 
243  // Init PLL
244  // Use the PLL multiplier setting to get 80MHz output from our 8MHz input
245  // Equation: PLL output clock frequency x 2 = input clock frequency x (hspllParam.multiplier+1)
246  // Input clock frequency = 8MHz
247  // Desired PLL output clock frequency = 80MHz
248  // hspllParam.multipler = 19
249  HSPLL_initParam hspllParam = {0};
250 // hspllParam.multiplier = PLLM_19_H;
251  hspllParam.multiplier = 0x004c;
252  hspllParam.frequency = HSPLL_GREATER_THAN_6MHZ;
253  HSPLL_init(HSPLL_BASE, &hspllParam);
254 
255  // Power up the UUPS to start the PLL
256  UUPS_turnOnPower(UUPS_BASE, UUPS_POWERUP_TRIGGER_SOURCE_USSPWRUP);
257 
258  // Wait for UUPS to power up
259  while(UUPS_getPowerModeStatus(UUPS_BASE) != UUPS_POWERMODE_READY);
260 
261  // Wait for PLL to lock
262  while(HSPLL_isLocked(HSPLL_BASE) == HSPLL_UNLOCKED);
263  /* ---End initialize the HSPLL and wait for it to lock--- */
264 }
265 
266 // Timer A4 interrupt service routine
267 #if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
268 #pragma vector = TIMER4_A0_VECTOR
269 __interrupt void Timer4_A0_ISR(void)
270 #elif defined(__GNUC__)
271 void __attribute__ ((interrupt(TIMER4_A0_VECTOR))) Timer4_A0_ISR (void)
272 #else
273 #error Compiler not supported!
274 #endif
275 {
276  // Stop the timer and wake from LPM
277  Timer_A_stop(TA4_BASE);
278  __bic_SR_register_on_exit(LPM3_bits | GIE);
280 }
281 
282 void setup_DMA()
283 {
284 
285  int i;
286  unsigned long SAPHPGC_addr, SAPHXPGCTL_addr;
287  SAPHPGC_addr = (unsigned long)(uintptr_t)(&SAPHPGC);
288  SAPHXPGCTL_addr = (unsigned long)(uintptr_t)(&SAPHXPGCTL);
289  // DMA2 and DMA3 triggered by PPG, DMA2 has higher priority
290  DMACTL1 = DMA2TSEL_27|DMA3TSEL_27;
291 
292  SAPH_A_configXPGParam saphAXPGParam = {0};
293  saphAXPGParam.eventType = SAPH_A_DMA_TRIGGER_EVENT;
294  saphAXPGParam.extendedMode = SAPH_A_DUAL_TONE_LOOP;
295  saphAXPGParam.extraPulses = 2;
296  SAPH_A_configureExtendedPPG(SAPH_A_BASE, &saphAXPGParam);
297 
298  SAPH_A_setXPGLowPeriod(SAPH_A_BASE, 16);
299  SAPH_A_setXPGHighPeriod(SAPH_A_BASE, 16);
300 
301  // Repeated block transfer, increase src address, increase dst address
302  DMA_initParam dmaParam = {0};
303  dmaParam.channelSelect = DMA_CHANNEL_2;
304  dmaParam.transferModeSelect = DMA_TRANSFER_REPEATED_BLOCK;
305  DMA_init(&dmaParam);
306  DMA_setSrcAddress(DMA_CHANNEL_2, (uint32_t)(uintptr_t)&RAM_XE, DMA_DIRECTION_INCREMENT);
307  DMA_setDstAddress(DMA_CHANNEL_2, (uint32_t)(uintptr_t)&SAPHPGC, DMA_DIRECTION_INCREMENT);
308 
309  DMA_setTransferSize(DMA_CHANNEL_2, 3); // 3 registers per block
310  DMA_enableTransfers(DMA_CHANNEL_2);
311  // Write new SA and DA of DMA2
312  DMA_setSrcAddress(DMA_CHANNEL_2, (uint32_t)(uintptr_t)RAM_XE+3, DMA_DIRECTION_INCREMENT);
313  DMA_setDstAddress(DMA_CHANNEL_2, (uint32_t)(uintptr_t)&SAPHXPGCTL, DMA_DIRECTION_INCREMENT);
314 
315  // Repeated block transfer, increase src address, increase dst address
316  dmaParam.channelSelect = DMA_CHANNEL_3;
317  DMA_init(&dmaParam);
318  DMA_setSrcAddress(DMA_CHANNEL_3, (uint32_t)(uintptr_t)&RAM_DMA_CONFIG, DMA_DIRECTION_INCREMENT);
319  DMA_setDstAddress(DMA_CHANNEL_3, (uint32_t)(uintptr_t)&DMA2SA, DMA_DIRECTION_INCREMENT);
320 
321  DMA_setTransferSize(DMA_CHANNEL_3, 9); // 10 DMA registers
322  DMA_enableTransfers(DMA_CHANNEL_3);
323  // Write new SA of DMA3
324  DMA_setSrcAddress(DMA_CHANNEL_3, (uint32_t)(uintptr_t)RAM_DMA_CONFIG+9, DMA_DIRECTION_INCREMENT);
325 
326  // Setup RAM
327  // RAM to be transfered to DMA2 and DMA3 // DST Addresses
328  for (i = 0; i < 5; i++)
329  {
330  *(RAM_DMA_CONFIG+i*9) = (unsigned int)((unsigned long)(uintptr_t)(RAM_XE+(i+2)*3));// DMA2SA
331  *(RAM_DMA_CONFIG+1+i*9) = (unsigned int)(((unsigned long)(uintptr_t)(RAM_XE+(i+2)*3))>>16);// DMA2SAH
332  *(RAM_DMA_CONFIG+2+i*9) = (unsigned int)(SAPHPGC_addr); // DMA2DA
333  *(RAM_DMA_CONFIG+3+i*9) = 0x0000; // DMA2DAH
334  *(RAM_DMA_CONFIG+4+i*9) = 0x0003; // DMA2SZ
335  *(RAM_DMA_CONFIG+5+i*9) = 0x0000; // dummy
336  *(RAM_DMA_CONFIG+6+i*9) = 0x0000; // dummy
337  *(RAM_DMA_CONFIG+7+i*9) = 0x5000|DMASRCINCR|DMADSTINCR|DMAEN; // DMA3CTL
338  *(RAM_DMA_CONFIG+8+i*9) = (unsigned int)(unsigned long)(uintptr_t)(RAM_DMA_CONFIG+(i+2)*9); // DMA3SA
339  }
340  for (i = 0; i < 2; i++)
341  {
342  *(RAM_DMA_CONFIG + 11+i*18) = (unsigned int)(SAPHXPGCTL_addr); // DMA2DA
343  }
344 
345  // RAM to be transfered to XCTL or PGC
346  for (i = 0; i < 3; i++)
347  {
348  *(RAM_XE+i*6) = epulse[i]; // SPULSE EPULSE SAPHPGC
349  *(RAM_XE+1+i*6) = lper[i]; // SAPHLPGPER
350  *(RAM_XE+2+i*6) = hper[i]; // SAPHHPGPER
351  }
352  for (i = 0; i < 2; i++)
353  {
354  *(RAM_XE+3+i*6) = 0x7000|xpulse[i];// DMA_EN XMOD XPULSE SAPHXPGCTL
355  *(RAM_XE+4+i*6) = xlper[i]; // SAPHAXLPGPER
356  *(RAM_XE+5+i*6) = xhper[i]; // SAPHAXHPGPER
357  }
358 
359  // Stop
360  *(RAM_XE+15) = 0x6000; // XMOD 2
361  *(RAM_XE+15+1) = 0x0000;
362  *(RAM_XE+15+2) = 0x0000;
363 }
364 
MPU_initThreeSegmentsParam param
__delay_cycles(500000)
uint16_t RAM_DMA_CONFIG[60]
uint16_t xhper[2]
uint16_t hper[3]
__no_operation()
__bic_SR_register_on_exit(LPM3_bits|GIE)
uint16_t RAM_XE[20]
int main(void)
uint16_t xlper[2]
uint16_t xpulse[2]
uint16_t epulse[3]
DMA_initParam dmaParam
void HSPLL_routine(void)
uint16_t lper[4]